package com.wmsafe.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.wmsafe.common.utils.JwtUtil;
import com.wmsafe.common.utils.ResponseData;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.AntPathMatcher;
import reactor.core.publisher.Flux;

import java.nio.charset.StandardCharsets;

public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory<Object> {

    @Value(value = "${white-list:}") //从nacos中的cloud-gateway-service-6008.yml中拿到白名单列表
    private String whiteListStr;

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String pathString = request.getPath().toString();

            if(StringUtils.isNotEmpty(whiteListStr)){
                String[] whitelist = whiteListStr.split(",");
                //使用 AntPathMatcher 类来实现路径的模式匹配 AntPathMatcher 是 Spring 框架中提供的路径匹配工具类，支持常用的 Ant 风格的路径匹配规则
                AntPathMatcher pathMatcher = new AntPathMatcher();

                for (String whiteUrl : whitelist) {
                    //匹配是从下标 0 开始匹配的 第一个参数是白名单 第二个参数是当前请求的路径
                    boolean match = pathMatcher.match(whiteUrl, pathString);
                    if(match){
                        return chain.filter(exchange);//是在白名单，后面放行
                    }
                }
            }

            HttpHeaders headers = request.getHeaders();
//            String authorizationHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);
            String tokenHeader = headers.getFirst("token");

//            if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            if (tokenHeader != null) {
//                String jwt = authorizationHeader.substring(7);
                try {
                    Claims claims = JwtUtil.parseJWT(tokenHeader);
                    String userId = claims.getSubject();

                    ServerHttpRequest.Builder builder = request.mutate();
                    builder.header("X-Forwarded-UserId", userId);

                    ServerHttpRequest newRequest = builder.build();
                    return chain.filter(exchange.mutate().request(newRequest).build());
                } catch (Exception e) {
                    // 设置 HTTP 响应码和响应内容
                    exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                    // 设置 HTTP 响应头 Content-Type 的值为 application/json
                    exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
                    // 定义返回的错误信息
                    ResponseData responseData = new ResponseData(500,null,"token不存在或已失效");

                    byte[] bytes = JSONObject.toJSONString(responseData).getBytes(StandardCharsets.UTF_8);
                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                    return exchange.getResponse().writeWith(Flux.just(buffer));
//                    return exchange.getResponse().setComplete();
                }
            } else {
                // 设置 HTTP 响应码和响应内容
                exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                // 设置 HTTP 响应头 Content-Type 的值为 application/json
                exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
                // 定义返回的错误信息
                ResponseData responseData = new ResponseData(500,null,"未鉴权的请求");

                byte[] bytes = JSONObject.toJSONString(responseData).getBytes(StandardCharsets.UTF_8);
                DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                return exchange.getResponse().writeWith(Flux.just(buffer));
//                return exchange.getResponse().setComplete();
            }
        };
    }

}
